#include "LogicSystem.hpp"
#include "HttpConnection.hpp"
#include "MysqlDao.hpp"
#include "MysqlMgr.hpp"
#include "RedisMgr.hpp"
#include "StatusGrpcClient.h"
#include "VerifyGrpcClient.hpp"
#include "const.hpp"
#include <boost/beast/core/buffers_to_string.hpp>
#include <boost/beast/core/ostream.hpp>
#include <boost/beast/http.hpp>
#include <boost/beast/http/field.hpp>
#include <iostream>
#include <json/json.h>
#include <json/reader.h>
#include <json/value.h>
#include <memory>
#include <string>
namespace beast = boost::beast;
LogicSystem::LogicSystem() {
  // 注册 GET 测试请求
  RegGet("/get_test", [](std::shared_ptr<HttpConnection> connection) {
    beast::ostream(connection->_response.body())
        << "receive get_test req" << std::endl;
    int i = 0;
    for (auto &item : connection->_get_params) {
      i++;
      beast::ostream(connection->_response.body())
          << i << " " << item.first << ":" << item.second << std::endl;
      ;
    }
  });

  // 获取验证码接口
  RegPost("/get_verifycode", [](std::shared_ptr<HttpConnection> connection) {
    auto body_str =
        boost::beast::buffers_to_string(connection->_request.body().data());
    std::cout << "receive body is " << body_str << std::endl;
    connection->_response.set(http::field::content_type, "text/json");
    // 解析数据
    Json::Reader reader;
    Json::Value root;
    Json::Value src_root;
    if (!reader.parse(body_str, src_root)) {
      root["error"] = ErrorCodes::JsonError;
      std::cout << "Failed to parse Json data!" << std::endl;
      std::string jsonstr = root.toStyledString();
      beast::ostream(connection->_response.body()) << jsonstr;
      return true;
    }
    if (!src_root.isMember("email")) {
      root["error"] = ErrorCodes::JsonError;
      std::cout << "Failed to parse Json data!" << std::endl;
      std::string jsonstr = root.toStyledString();
      beast::ostream(connection->_response.body()) << jsonstr;
      return true;
    }
    auto email = src_root["email"].asString();
    // grpc调用验证码发送功能
    message::GetVerifyRsp rsp =
        VerifyGrpcClient::GetInstance()->GetVerifyCode(email);
    std::cout << "email is " << rsp.email() << std::endl;
    root["error"] = rsp.error();
    root["email"] = rsp.email();
    std::string jsonstr = root.toStyledString();
    beast::ostream(connection->_response.body()) << jsonstr;
    return true;
  });

  // 用户注册接口
  RegPost("/user_register", [](std::shared_ptr<HttpConnection> connection) {
    auto body_str =
        boost::beast::buffers_to_string(connection->_request.body().data());
    std::cout << "receive body is " << body_str << std::endl;
    connection->_response.set(http::field::content_type, "text/json");
    // 解析数据
    Json::Reader reader;
    Json::Value root;
    Json::Value src_root;
    if (!reader.parse(body_str, src_root)) {
      root["error"] = ErrorCodes::JsonError;
      std::cout << "Failed to parse Json data!" << std::endl;
      std::string jsonstr = root.toStyledString();
      beast::ostream(connection->_response.body()) << jsonstr;
      return true;
    }
    // 判断json是否包含邮箱
    if (!src_root.isMember("email")) {
      root["error"] = ErrorCodes::JsonError;
      std::cout << "Failed to parse Json data!" << std::endl;
      std::string jsonstr = root.toStyledString();
      beast::ostream(connection->_response.body()) << jsonstr;
      return true;
    }
    std::string email = src_root["email"].asString();
    // 判断字段中是否存在验证码
    if (!src_root.isMember("verifycode")) {
      root["error"] = ErrorCodes::JsonError;
      std::cout << "Failed to parse Json data!" << std::endl;
      std::string jsonstr = root.toStyledString();
      beast::ostream(connection->_response.body()) << jsonstr;
      return true;
    }
    // 从redis数据库中取出邮箱对应的验证码
    std::string verifyCode;
    // 验证码过期
    if (!RedisMgr::GetInstance()->Get(CODEPREFIX + email, verifyCode)) {
      std::cout << "get verify code expired." << std::endl;
      root["error"] = ErrorCodes::VerifyExpired;
      std::string json_str = root.toStyledString();
      beast::ostream(connection->_response.body()) << json_str;
      return true;
    }
    // 验证码不相同
    if (src_root["verifycode"].asString() != verifyCode) {
      std::cout << "verify code error." << std::endl;
      root["error"] = ErrorCodes::VerifyCodeError;
      std::string json_str = root.toStyledString();
      beast::ostream(connection->_response.body()) << json_str;
      return true;
    }
    // 验证码相同
    std::cout << "verify code success." << std::endl;
    // 查找数据库判断用户是否存在
    std::string user = src_root["user"].asString();
    std::string pwd = src_root["passwd"].asString();
    int uid = MysqlMgr::GetInstance()->RegUser(user, email, pwd);
    if (uid == -1) {
      std::cout << "user or email exist." << std::endl;
      root["error"] = ErrorCodes::UserExist;
      std::string json_str = root.toStyledString();
      beast::ostream(connection->_response.body()) << json_str;
      return true;
    }
    root["error"] = ErrorCodes::Success;
    root["uid"] = uid;
    root["email"] = email;
    root["user"] = user;
    root["password"] = pwd;
    root["verifycode"] = verifyCode;
    std::string json_str = root.toStyledString();
    beast::ostream(connection->_response.body()) << json_str;
    return true;
  });

  // 用户重置密码接口
  RegPost("/reset_pwd", [](std::shared_ptr<HttpConnection> connection) {
    // 1.获取消息体
    std::string body_str =
        beast::buffers_to_string(connection->_request.body().data());
    std::cout << "receive body is " << body_str << std::endl;
    // 2.设置返回数据格式
    connection->_response.set(http::field::content_type, "text/json");
    // 3.解析消息体
    Json::Reader reader;
    Json::Value root;
    Json::Value src_root;
    if (!reader.parse(body_str, src_root)) {
      root["error"] = ErrorCodes::JsonError;
      std::cout << "Failed to parse Json data!" << std::endl;
      std::string jsonstr = root.toStyledString();
      beast::ostream(connection->_response.body()) << jsonstr;
      return true;
    }
    std::string user = src_root["user"].asString();
    std::string email = src_root["email"].asString();
    std::string verifyCode = src_root["verifyCode"].asString();
    std::string password = src_root["password"].asString();
    // 4.查询验证码是正确
    std::string _verifyCode;
    if (!RedisMgr::GetInstance()->Get(CODEPREFIX + email, _verifyCode)) {
      // 验证码过期
      std::cout << "get verify code expired." << std::endl;
      root["error"] = ErrorCodes::VerifyExpired;
      std::string json_str = root.toStyledString();
      beast::ostream(connection->_response.body()) << json_str;
      return true;
    }
    if (_verifyCode != verifyCode) {
      std::cout << _verifyCode;
      // 验证码错误
      std::cout << "verify code error." << std::endl;
      root["error"] = ErrorCodes::VerifyCodeError;
      std::string json_str = root.toStyledString();
      beast::ostream(connection->_response.body()) << json_str;
      return true;
    }
    // 验证码正确 查询邮箱是否存在
    if (!MysqlMgr::GetInstance()->CheckEmail(email)) {
      std::cout << "Email not exists." << std::endl;
      root["error"] = ErrorCodes::EmailError;
      std::string json_str = root.toStyledString();
      beast::ostream(connection->_response.body()) << json_str;
      return true;
    }
    if (!MysqlMgr::GetInstance()->UpdatePwd(email, password)) {
      // 数据库更新错误
      std::cout << "DataBase update error." << std::endl;
      root["error"] = ErrorCodes::DataBaseError;
      std::string json_str = root.toStyledString();
      beast::ostream(connection->_response.body()) << json_str;
      return true;
    }
    std::cout << "reset password success.\n";
    root["error"] = ErrorCodes::Success;
    root["email"] = email;
    root["user"] = user;
    root["password"] = password;
    std::string json_str = root.toStyledString();
    beast::ostream(connection->_response.body()) << json_str;
    return true;
  });

  // 用户登录接口
  RegPost("/user_login", [](std::shared_ptr<HttpConnection> connection) {
    connection->_response.set(beast::http::field::content_type, "text/json");
    std::string body_str =
        beast::buffers_to_string(connection->_request.body().data());
    std::cout << "receive body is " << body_str << std::endl;
    Json::Value root;
    Json::Value src_root;
    Json::Reader reader;
    if (!reader.parse(body_str, src_root)) {
      std::cout << "Failed to parse Json data!" << std::endl;
      root["error"] = ErrorCodes::JsonError;
      beast::ostream(connection->_response.body()) << root.toStyledString();
      return true;
    }
    std::string email = src_root["email"].asString();
    std::string pwd = src_root["password"].asString();
    UserInfo userInfo;
    if (!MysqlMgr::GetInstance()->CheckPwd(email, pwd, userInfo)) {
      std::cout << "Email and password do not match." << std::endl;
      root["error"] = ErrorCodes::PasswdInvalid;
      beast::ostream(connection->_response.body()) << root.toStyledString();
      return true;
    }
    // 查询StatusServer找到合适的连接
    auto reply = StatusGrpcClient::GetInstance()->GetChatServer(userInfo.uid);
    if (reply.error()) {
      std::cout << "grpc get chat server failed, error is " << reply.error()
                << std::endl;
      root["error"] = ErrorCodes::RPCFailed;
      beast::ostream(connection->_response.body()) << root.toStyledString();
      return true;
    }
    std::cout << "succeed to load userInfo uid is " << userInfo.uid
              << std::endl;
    root["error"] = ErrorCodes::Success;
    root["email"] = email;
    root["uid"] = userInfo.uid;
    root["token"] = reply.token();
    root["host"] = reply.host();
    root["port"] = reply.port();
    beast::ostream(connection->_response.body()) << root.toStyledString();
    return true;
  });
}
// 注册不同路径对应的处理函数
void LogicSystem::RegGet(std::string url, HttpHandler handle) {
  _get_handles.insert({url, handle});
}

bool LogicSystem::HandleGet(std::string path,
                            std::shared_ptr<HttpConnection> connection) {
  if (_get_handles.find(path) == _get_handles.end()) {
    return false;
  }
  _get_handles[path](connection);
  return true;
}

bool LogicSystem::HandlePost(std::string path,
                             std::shared_ptr<HttpConnection> connection) {
  if (_post_handles.find(path) == _post_handles.end()) {
    return false;
  }
  _post_handles[path](connection);
  return true;
}

void LogicSystem::RegPost(std::string path, HttpHandler handler) {
  _post_handles.insert({path, handler});
}

LogicSystem ::~LogicSystem() {}